package com.ahncnk.powermonitor.admin.auth.service;

import com.ahncnk.powermonitor.admin.AppConfig;
import com.ahncnk.powermonitor.admin.auth.domain.dto.JwtVerifyResult;
import com.ahncnk.powermonitor.admin.auth.domain.dto.Token;
import com.ahncnk.powermonitor.admin.users.domain.UserPrincipal;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.UUID;

/**
 * AuthService
 *
 * @author lipei
 */
@Service
public class AuthService {
    @Resource
    private AppConfig appConfig;


    /**
     * 将登录用户加密成jwt，并分成两个Cookie存放。
     */
    public Token sign(UserPrincipal user) {
        Duration expireTimeout = appConfig.getAuth().getExpireTimeout();
        Instant expiration = Instant.now().plus(expireTimeout);
        Algorithm algorithm = Algorithm.HMAC256(getAccessTokenPrivateKey());
        String jwt = JWT.create()
                .withJWTId(UUID.randomUUID().toString())
                .withIssuer(appConfig.getAppName())
                .withSubject(String.valueOf(user.getId()))
                .withClaim("username", user.getUsername())
                .withExpiresAt(Date.from(expiration))
                .withIssuedAt(new Date())
                .sign(algorithm);
        return new Token(jwt, appConfig.getAppName(), expireTimeout);
    }

    /**
     * 验证jwt.
     */
    public JwtVerifyResult verify(String jwt) throws JWTVerificationException {
        Algorithm algorithm = Algorithm.HMAC256(getAccessTokenPrivateKey());
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(jwt);
        return new JwtVerifyResult(decodedJWT, new JwtUserPrincipal(
                Integer.parseInt(decodedJWT.getSubject()),
                decodedJWT.getClaim("username").asString()));
    }

    /**
     * 存放 signature 信息的cookie名.
     */
    public String getSignatureCookieName() {
        return Token.signatureCookieName(appConfig.getAppName());
    }

    /**
     * 存放 header.payload 信息的cookie名.
     */
    public String getHeaderAndPayloadCookieName() {
        return Token.headerAndPayloadCookieName(appConfig.getAppName());
    }

    /**
     * 获取token加密密钥。
     */
    private String getAccessTokenPrivateKey() {
        return appConfig.getAuth().getSecret();
    }

    private class JwtUserPrincipal implements UserPrincipal {
        private final Integer id;
        private final String username;

        private JwtUserPrincipal(Integer id, String username) {
            this.id = id;
            this.username = username;
        }

        @Override
        public Integer getId() {
            return id;
        }

        @Override
        public String getUsername() {
            return username;
        }
    }
}
